package cn.remex.core.util;

import cn.remex.RemexConstants;
import cn.remex.core.exception.ServiceCode;
import cn.remex.core.exception.StringHandleException;
import org.apache.oro.text.regex.MalformedPatternException;
import org.apache.oro.text.regex.MatchResult;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.PatternMatcher;
import org.apache.oro.text.regex.PatternMatcherInput;
import org.apache.oro.text.regex.Perl5Matcher;
import org.apache.oro.text.regex.Perl5Substitution;
import org.apache.oro.text.regex.Util;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.function.BiConsumer;

/**
 * String 处理工具类
 */
public class StringHelper implements RemexConstants {
	private static HashMap<String, Pattern> patterns = new HashMap<String, Pattern>();

	private static HashMap<Class<?>, String> ClassAbbreviation = new HashMap<Class<?>, String>();

	public static String obtainStackMsg(Throwable t, int maxLength){
		try {
			ByteArrayOutputStream buf = new java.io.ByteArrayOutputStream();
			t.printStackTrace(new java.io.PrintWriter(buf, true));
			String expMessage = buf.toString();
			buf.close();
			return expMessage.substring(0, maxLength<expMessage.length()?maxLength:expMessage.length());
		} catch (IOException e) {
			return t.toString();
		}
	}
	/**
	 * 设置字符串等宽，及对齐方式
	 *
	 * @param sourString 要处理的String
	 * @param width      列宽
	 * @param textAlign  left or right 左或右
	 * @return String 字符串
	 */
	public static String aequilate(final String sourString, final int width, final String... textAlign) {
		boolean textAlignLeft = "left".equals(textAlign != null && textAlign.length > 0 ? textAlign[0] : "left") ? true
				: false;
		StringBuilder sb = new StringBuilder(sourString);
		if (sourString.length() < width) {
			for (int i = width - sourString.length(); i > 0; i--) {
				if (textAlignLeft) {
					sb.append(" ");
				} else {
					sb.insert(0, " ");
				}
			}
		}
		return sb.toString();
	}

	/**
	 * 将字符串中的半角数字替换为全角数字
	 *
	 * @param string 要处理的字符串
	 * @return String 处理后的字符串
	 */
	public static String fomatString(final String string) {
		return string.replaceAll("0", "０").replaceAll("1", "１").replaceAll("2", "２").replaceAll("3", "３")
				.replaceAll("4", "４").replaceAll("5", "５").replaceAll("6", "６").replaceAll("7", "７")
				.replaceAll("8", "８").replaceAll("9", "９");
	}

	/**
	 * 取类名的所有大写字母
	 *
	 * @param type 类名
	 * @return String 返回的字符串
	 */
	public static String getAbbreviation(final Type type) {
		if (type instanceof Class<?>) {
			String abbr = ClassAbbreviation.get(type);
			if (null == abbr) {
				String sn = getClassSimpleName(type);
				abbr = sn.replaceAll("[^A-Z]", "");
				ClassAbbreviation.put((Class<?>) type, abbr);
			}
			return abbr;
		} else {
			throw new StringHandleException(ServiceCode.FAIL, "因为此Type非Class类型，无法为Type" + type.toString() + "类指定缩写！");
			// return null;//never arrived here
		}

	}

	/**
	 * 为类简名
	 *
	 * @param type 类名
	 * @return String 返回的类简名
	 */

	public static String getClassSimpleName(final Type type) {
		if (type instanceof Class<?>) {
			String sn = ((Class<?>) type).getSimpleName();
			return sn.split("\\$\\$EnhancerByCGLIB\\$\\$")[0];
		} else {
			throw new StringHandleException(ServiceCode.FAIL, "因为此Type非Class类型，无法为Type" + type.toString() + "类简名！");
			// return null;//never arrived here
		}

	}

	/**
	 * 获取类名
	 *
	 * @param type 类名
	 * @return String 字符串
	 */
	public static String getClassName(final Type type) {
		if (type instanceof Class<?>) {
			String sn = ((Class<?>) type).getName();
			return sn.split("\\$\\$EnhancerByCGLIB\\$\\$")[0];
		} else {
			throw new StringHandleException(ServiceCode.FAIL, "因为此Type非Class类型，无法为Type" + type.toString() + "类简名！");
			// return null;//never arrived here
		}

	}

	/**
	 * 字符串第一个字母转为小写
	 *
	 * @param string 字符串
	 * @return String 转化结果
	 */
	public static String lowerFirstLetter(final String string) {
		StringBuilder sb = new StringBuilder();
		return sb.append(string.substring(0, 1).toLowerCase()).append(string.substring(1)).toString();
	}

	/**
	 * 验证字符串是否匹配正则表达式
	 *
	 * @param string               被测试的字符串
	 * @param regex                匹配的正则表达式
	 * @param notMatchExceptionMsg 没有匹配时报异常的信息
	 * @return　MatchResult 匹配操作的结果
	 */
	public static MatchResult match(final String string, final String regex, final String notMatchExceptionMsg) {
		PatternMatcher m = new Perl5Matcher();
		Pattern p = obtainPattern(regex);
		if (!m.contains(string, p) && null != notMatchExceptionMsg) {
			throw new StringHandleException(ServiceCode.FAIL, notMatchExceptionMsg);
		}
		return m.getMatch();
	}

	private static synchronized Pattern obtainPattern(String regex) {
		Pattern p = patterns.get(regex);
		if (null == p) {
			try {
				p = compiler.compile(regex);
				patterns.put(regex, p);
			} catch (MalformedPatternException e) {
				throw new StringHandleException(ServiceCode.FAIL, "连接正则表达式发生异常！", e);
			}
		}
		return p;
	}

	public static int forEachMatch(final String string, final String regex, BiConsumer<MatchResult, Boolean> matchConsumer) {
		PatternMatcher m = new Perl5Matcher();
		Pattern p = obtainPattern(regex);
		PatternMatcherInput input = new PatternMatcherInput(string);
		int len = string.length();
		while (m.contains(input, p)) {
			matchConsumer.accept(m.getMatch(), input.endOfInput());
		}

		return input.getEndOffset();
	}

	/**
	 * @param searchRegx   searchRegx
	 * @param string       string
	 * @param replaceRegx  替换的表达式，支持$1来获取查找到的组号。
	 * @param replaceTimes -1 替换所有，否则替换replaceTimes次
	 * @return String
	 */
	public static String substitute(final String string, final String searchRegx, final String replaceRegx, final int replaceTimes) {
		PatternMatcher m = new Perl5Matcher();
		Pattern sp = obtainPattern(searchRegx);
		String result = Util.substitute(m, sp, new Perl5Substitution(replaceRegx), string, replaceTimes);
		return result;
	}

	/**
	 * 将字符串指定长度后三位用...代替,并将半角替换为全角数字
	 *
	 * @param string    字符串
	 * @param maxLength 最大长度
	 * @return 处理后的string
	 */
	public static String substringByMaxLength(String string, final int maxLength) {
		if (string.length() > maxLength) {
			string = string.substring(0, maxLength - 3) + "...";
		}
		return string.replaceAll("0", "０").replaceAll("1", "１").replaceAll("2", "２").replaceAll("3", "３")
				.replaceAll("4", "４").replaceAll("5", "５").replaceAll("6", "６").replaceAll("7", "７")
				.replaceAll("8", "８").replaceAll("9", "９");
	}

	/**
	 * 设置起始位置截取字符串，并将半角数字替换为全角数字
	 *
	 * @param string 要处理的字符串
	 * @param start  起始位置
	 * @param end    终止
	 * @return String 处理后的字符串
	 */
	public static String substringByStartAndEnd(String string, final int start, int end) {
		if (start < 0 || end <= start) {
			return "字符长度设置错误!";
		}
		if (end > string.length()) {
			end = string.length();
		}
		string = string.substring(start, end);
		return string.replaceAll("0", "０").replaceAll("1", "１").replaceAll("2", "２").replaceAll("3", "３")
				.replaceAll("4", "４").replaceAll("5", "５").replaceAll("6", "６").replaceAll("7", "７")
				.replaceAll("8", "８").replaceAll("9", "９");
	}

	/**
	 * 将字符串首字母转为大写
	 *
	 * @param string 要处理的字符串
	 * @return String 处理后的字符串
	 */
	public static String upperFirstLetter(final String string) {
		return string.substring(0, 1).toUpperCase() + string.substring(1);
	}

	public static String exCharset(String str, String fromCharset, String toCharset) {
		try {
			return new String(str.getBytes(fromCharset), toCharset);
		} catch (UnsupportedEncodingException e) {
			throw new StringHandleException(ServiceCode.FAIL, "转换String时字符集不受支持", e);
		}
	}

	public static String urlEncode(String str, String charset) {
		try {
			return URLEncoder.encode(str, charset);
		} catch (UnsupportedEncodingException e) {
			throw new StringHandleException(ServiceCode.FAIL, "URLEncode时，转换String时字符集不受支持", e);
		}
	}

	public static String urlDecode(String data, String charset) {
		try {
			data = data.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
			data = data.replaceAll("\\+", "%2B");
			data = URLDecoder.decode(data, charset);
			return data;
		} catch (UnsupportedEncodingException e) {
			throw new StringHandleException(ServiceCode.FAIL, "URLDecode时，转换String时字符集不受支持", e);
		}
	}


	public static long writeToStream(String requestBody, String charset, OutputStream outputStream) {
		long length=-1;
		try {
			if (!Judgment.nullOrBlank(requestBody)) {
				byte[] buffer = requestBody.getBytes(charset);
				length = buffer.length;
				outputStream.write(buffer);
			}
			outputStream.flush();
		} catch (Exception e) {
			throw new StringHandleException(ServiceCode.FAIL, "字符串写入流时发生错误！", e);
		}
		return length;
	}

	public static String readFromStream(String charset, InputStream inputStream) {
		try {
			return new String(readFromStream(inputStream), charset);
		} catch (UnsupportedEncodingException e) {
			throw new StringHandleException(ServiceCode.FAIL, "读取流从byte中提出String时不支持字符集", e);
		}

	}
	public static byte[] readFromStream(InputStream inputStream) {
		try {
			byte[] buffer = new byte[1024]; // 数据缓冲区
			int count; // 每个缓冲区的实际数据长度
			ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 请求数据存放对象
			BufferedInputStream bufferedInput = new BufferedInputStream(inputStream);
			while ((count = bufferedInput.read(buffer)) != -1) {
				baos.write(buffer, 0, count);
			}
			byte[] bytes = baos.toByteArray(); // 得到一个byte数组,提供给平台
			return bytes;
		} catch (Exception e) {
			throw new StringHandleException(ServiceCode.FAIL, "读入流时发生错误", e);
		}

	}
}
